use anyhow::Result;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use tracing::{Level, event};

use crate::{
    model::AppQuery,
    sync::{USER_AGENT, code},
};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubstanceData {
    pub id: String,
    pub title: String,
    pub sub_title: Option<String>,
    pub name: Option<String>,
    pub data: Vec<AppQuery>,
}

impl SubstanceData {
    pub fn say_my_name(&self) -> String {
        format!(
            "{}{}{}",
            self.title,
            self.sub_title
                .as_ref()
                .map(|s| format!(" - {}", s))
                .unwrap_or_default(),
            self.name
                .as_ref()
                .map(|s| format!(" ({})", s))
                .unwrap_or_default()
        )
    }
}

/// 统一的用来 从 card 里获取 应用信息的 函数
fn get_app_from_card(
    card: &JsonValue,
    apps: &mut Vec<AppQuery>,
    title: &mut Option<String>,
    sub_title: &mut Option<String>,
    name: &mut Option<String>,
) {
    let data_cards = card.as_object().expect("card not object")["data"]
        .as_array()
        .expect("data not array");
    match card["type"].as_str().unwrap_or("") {
        "com.huawei.hmsapp.appgallery.verticallistcard" => {
            // 竖向列表卡片
            for card in data_cards {
                if let Some(app_id) = card.get("appId") {
                    apps.push(AppQuery::app_id(app_id.as_str().expect("appId not str")));
                }
            }
        }
        "com.huawei.hmos.appgallery.scenariolistcard.landing"
        | "com.huawei.hmos.appgallery.whiteverticalslidercard.landing"
        | "com.huawei.hmsapp.appgallery.appiconrollingcard.landing" => {
            // 这玩意是肯定有第一个的
            let first = &data_cards[0].as_object().expect("first not object");
            // 考虑到有概率他就是个title, 先把 title 拿了
            if let Some(title_obj) = first.get("title") {
                *title = title_obj.as_str().map(|s| s.to_string());
            }
            if let Some(sub_title_obj) = first.get("subTitle") {
                *sub_title = sub_title_obj.as_str().map(|s| s.to_string());
            }
            if let Some(name_obj) = first.get("name") {
                *name = name_obj.as_str().map(|s| s.to_string());
            }

            if !first.contains_key("refsList_app") {
                // 有 verticallistcard 的, landing 里面就没有 app 了
                return;
            }
            // 里面有可能有个 refsList_app 是个数组，里面是 appId
            let app_list = first["refsList_app"]
                .as_array()
                .expect("refsList_app not array");
            for app in app_list {
                if let Some(app_id) = app.get("appId") {
                    apps.push(AppQuery::app_id(app_id.as_str().expect("appId not str")));
                }
            }
        }
        "com.huawei.hmsapp.appgallery.subjectappbigcard.landing" => {
            // 大卡片, 只是用来获取标题, 吗?
            for card in data_cards {
                if let Some(title_obj) = card.get("title") {
                    *title = title_obj.as_str().map(|s| s.to_string());
                }
                if let Some(sub_title_obj) = card.get("subTitle") {
                    *sub_title = sub_title_obj.as_str().map(|s| s.to_string());
                }
                if let Some(name_obj) = card.get("name") {
                    *name = name_obj.as_str().map(|s| s.to_string());
                }
                if let Some(app_list) = card.get("refsList_app_short") {
                    // 想不到吧! 我还能复用! (华为我谢谢你)
                    let app_list = app_list.as_array().expect("refsList_app_short not array");
                    for app in app_list {
                        if let Some(app_id) = app.get("appId") {
                            apps.push(AppQuery::app_id(app_id.as_str().expect("appId not str")));
                        }
                    }
                }
                // refs_app
                // 我谢谢你, 复用大师华为
                if let Some(app) = card.get("refs_app")
                    && let Some(app_id) = app.get("appId")
                {
                    apps.push(AppQuery::app_id(app_id.as_str().expect("appId not str")));
                }
            }
        }
        "com.huawei.hmos.appgallery.substancebottomappcard"
        | "com.huawei.hmsapp.appgallery.hosthiddenappcard" => {
            // 独立 app 的另两种形式的卡片
            // 例子: https://appgallery.huawei.com/substance/detail?id=515d0b1e352f464b9fefc0a281af0474s
            for card in data_cards {
                // refs_app
                if let Some(app) = card.get("refs_app")
                    && let Some(app_id) = app.get("appId")
                {
                    apps.push(AppQuery::app_id(app_id.as_str().expect("appId not str")));
                }
                // 与此同时, refs app 也有两种形式
                // 第二种形式例子:
                // https://appgallery.huawei.com/substance/detail?id=c2cf94392cad44439416b0c517c9c322
                if let Some(app_list) = card.get("list")
                    && let Some(app_list) = app_list.as_array()
                {
                    for obj in app_list {
                        // 还要套一层 refs_app
                        if let Some(ref_app) = obj.get("refs_app")
                            && let Some(app_id) = ref_app.get("appId")
                        {
                            apps.push(AppQuery::app_id(app_id.as_str().expect("appId not str")));
                        }
                    }
                }
            }
        }
        "com.huawei.hmsapp.appgallery.paragraphtitlecard"
        | "com.huawei.hmsapp.appgallery.paragraphtextcard"
        | "com.huawei.hmsapp.appgallery.paragraphsubtitlecard"
        | "com.huawei.hmsapp.appgallery.paragraphreferencecard"
        | "com.huawei.hmsapp.appgallery.videoitemcard"
        | "com.huawei.hmsapp.appgallery.singleappcard"
        | "com.huawei.hmsapp.appgallery.articletitlecard"
        | "com.huawei.hmsapp.appgallery.substancerelatedtopiccard"
        | "com.huawei.hmsapp.appgallery.substancedetailimagecard" => {
            // 标记一下已知
        }
        t => {
            // 标记一下未知
            println!("Unknown card type: {}", t);
        }
    }
}

async fn get_more_substance(
    client: &reqwest::Client,
    api_url: &str,
    card_id: impl ToString,
    title: &mut Option<String>,
    sub_title: &mut Option<String>,
    name: &mut Option<String>,
) -> Result<Vec<AppQuery>> {
    let mut has_more = true;
    // 从 2 开始
    let mut page_num = 2;
    let mut apps = Vec::new();
    let target_url = format!("{api_url}/harmony/card-list");
    while has_more {
        let body = serde_json::json!({
            "dataId": card_id.to_string(),
            "locale": "zh",
            "pageNum": page_num,
            "pageSize": 25,
        });
        let token = code::GLOBAL_CODE_MANAGER.get_full_token().await;
        let response = client
            .post(&target_url)
            .header("Content-Type", "application/json")
            .header("User-Agent", USER_AGENT.to_string())
            .header("Interface-Code", token.interface_code)
            .header("identity-id", token.identity_id)
            .json(&body)
            .send()
            .await?;

        // 检查响应状态码
        if !response.status().is_success() {
            return Err(anyhow::anyhow!(
                "HTTP请求失败,状态码: {}\nurl: {} body: {}",
                response.status(),
                target_url,
                body
            ));
        }

        // 检查响应体是否为空
        let content_length = response.content_length().unwrap_or(0);
        if content_length == 0 {
            return Err(anyhow::anyhow!(
                "HTTP响应体为空 \nurl: {target_url} data: {body}"
            ));
        }

        let data = response.json::<serde_json::Value>().await?;
        has_more = data
            .get("hasMore")
            .and_then(|v| v.as_i64())
            .map(|v| v != 0)
            .unwrap_or(false);
        page_num += 1;

        // 检查 layoutData 是否存在且为数组
        let layout = match data.get("layoutData").and_then(|v| v.as_array()) {
            Some(arr) => arr,
            None => {
                event!(
                    Level::WARN,
                    "layoutData 不是数组或不存在: substance id: {}, 跳过此页",
                    card_id.to_string()
                );
                // 如果 layoutData 不是数组，但还有更多页，继续尝试
                continue;
            }
        };

        for card in layout {
            get_app_from_card(card, &mut apps, title, sub_title, name);
        }
    }

    Ok(apps)
}

/// 获取主题的内容
pub async fn get_app_from_substance(
    client: &reqwest::Client,
    api_url: &str,
    substance_id: impl ToString,
) -> Result<(SubstanceData, JsonValue)> {
    let body = serde_json::json!({
        "pageId": format!("webAgSubstanceDetail|{}", substance_id.to_string()),
        "pageNum": 1,
        "pageSize": 100,
        "zone": "",
        "businessParam": { "animation": 0 }
    });

    let token = code::GLOBAL_CODE_MANAGER.get_full_token().await;
    let response = client
        .post(format!("{api_url}/harmony/page-detail"))
        .header("Content-Type", "application/json")
        .header("User-Agent", USER_AGENT.to_string())
        .header("Interface-Code", token.interface_code)
        .header("identity-id", token.identity_id)
        .json(&body)
        .send()
        .await?;

    // 检查响应状态码
    if !response.status().is_success() {
        return Err(anyhow::anyhow!(
            "HTTP请求失败,状态码: {}\nurl: {} body: {}",
            response.status(),
            api_url,
            body
        ));
    }

    // 检查响应体是否为空
    let content_length = response.content_length().unwrap_or(0);
    if content_length == 0 {
        return Err(anyhow::anyhow!(
            "HTTP响应体为空 \nurl: {api_url} data: {body}"
        ));
    }

    // 华为我谢谢你
    let data = {
        let raw = response.json::<serde_json::Value>().await?;
        let pages = &raw["pages"].as_array().expect("pages not array")[0];

        let card_list = &pages["data"]["cardlist"]
            .as_object()
            .expect("cardlist not object");

        let mut apps = Vec::new();

        let mut title = None;
        let mut sub_title = None;
        let mut name = None;

        if card_list["hasMore"].as_i64().unwrap_or(0) != 0 {
            let card_id = card_list["dataId"]
                .as_str()
                .expect("dataId not str")
                .to_string();
            let more_apps = get_more_substance(
                client,
                api_url,
                card_id,
                &mut title,
                &mut sub_title,
                &mut name,
            )
            .await?;
            apps.extend(more_apps);
        }
        let layouts = &card_list["layoutData"];

        // 检查 layoutData 是否为数组
        if let Some(layouts_array) = layouts.as_array() {
            for card in layouts_array {
                get_app_from_card(card, &mut apps, &mut title, &mut sub_title, &mut name);
            }
        } else {
            event!(
                Level::WARN,
                "layoutData 不是数组: substance id: {}, 类型: {:?}",
                substance_id.to_string(),
                layouts
            );
        }
        apps.sort();
        apps.dedup();

        (
            SubstanceData {
                id: substance_id.to_string(),
                title: title.unwrap_or_default(),
                sub_title,
                name,
                data: apps,
            },
            pages.clone(),
        )
    };

    Ok(data)
}

/// 同步专题
pub async fn sync_substance(
    client: &Client,
    db: &crate::db::Database,
    config: &crate::config::Config,
) -> anyhow::Result<()> {
    event!(Level::INFO, "开始同步专题");
    let substances = db.get_all_substance_id().await?;

    let mut query_apps = Vec::with_capacity(substances.len() * 3);
    let mut raw_datas = Vec::with_capacity(substances.len());

    event!(Level::INFO, "获取专题应用列表");
    for substance_id in substances {
        let apps = get_app_from_substance(client, config.api_url(), substance_id).await?;
        query_apps.extend(apps.0.data.clone());
        raw_datas.push(apps);
    }

    query_apps.sort();
    query_apps.dedup();

    event!(Level::INFO, "获取专题应用列表完成");

    event!(Level::INFO, "开始同步专题应用");
    // 使用 sync_all
    for app in query_apps.iter() {
        if let Err(e) = crate::sync::sync_app(client, db, config.api_url(), app, None, None).await {
            event!(Level::WARN, "保存 app 时错误 {e}")
        }
    }

    for (substance, raw_substance) in raw_datas {
        if let Err(e) = db.save_substance(&substance, &raw_substance, None).await {
            event!(Level::WARN, "保存 substance 时错误 {e}")
        }
    }
    event!(Level::INFO, "专题同步完成");
    Ok(())
}
